#!/usr/bin/env python3
from boututils.run_wrapper import shell_safe

import os
import shutil
import unittest


class TestCommandLineArgs(unittest.TestCase):
    command = "./command-args 2>stderr.log"

    def makeDirAndCopyInput(self, path):
        os.mkdir(path)
        shutil.copy("BOUT.inp", path)

    def setUp(self):
        try:
            os.remove("stderr.log")
        except OSError:
            pass
        shutil.rmtree("./data", ignore_errors=True)
        shutil.rmtree("./test", ignore_errors=True)
        shutil.rmtree("./test_copy", ignore_errors=True)

    # Teardown same as setup in case something went wrong with last run
    tearDown = setUp

    def testNoArgumentsNoDirectory(self):
        with self.assertRaises(RuntimeError):
            shell_safe(self.command, pipe=True)
        with open("stderr.log") as f:
            contents = f.read()
            self.assertIn('"data" does not exist', contents,
                          msg="FAIL: Error message not printed when missing input directory")

    def testHelpArgument(self):
        self.makeDirAndCopyInput("data")
        _, out = shell_safe(self.command + " --help", pipe=True)
        # Not a great test!
        self.assertNotIn("Writing options", out,
                         msg="FAIL: Attempting to write options")

    def testNoArgumentsDefaultDirectory(self):
        self.makeDirAndCopyInput("data")
        shell_safe(self.command, pipe=True)
        self.assertTrue(os.path.exists("data/BOUT.settings"),
                        msg="FAIL: No BOUT.settings file in data directory")
        self.assertTrue(os.path.exists("data/BOUT.log.0"),
                        msg="FAIL: No BOUT.log.0 file in data directory")

    def testShortLogArgument(self):
        self.makeDirAndCopyInput("data")
        shell_safe(self.command + " -l different.log", pipe=True)
        self.assertFalse(os.path.exists("data/BOUT.log.0"),
                         msg="FAIL: BOUT.log.0 file in data directory")
        self.assertTrue(os.path.exists("data/different.log.0"),
                        msg="FAIL: no different.log.0 file in data directory")

    def testLongLogArgument(self):
        self.makeDirAndCopyInput("data")
        shell_safe(self.command + " --log log", pipe=True)
        self.assertFalse(os.path.exists("data/BOUT.log.0"),
                         msg="FAIL: BOUT.log.0 file in data directory")
        self.assertTrue(os.path.exists("data/log.0"),
                        msg="FAIL: no log.0 file in data directory")

    def testDirectoryArgument(self):
        self.makeDirAndCopyInput("test")
        shell_safe(self.command + " -d test", pipe=True)
        self.assertTrue(os.path.exists("test/BOUT.settings"),
                        msg="FAIL: No BOUT.settings file in test directory")
        self.assertTrue(os.path.exists("test/BOUT.log.0"),
                        msg="FAIL: No BOUT.log.0 file in data directory")

    def testDirectoryArgumentOldSettingsFile(self):
        self.makeDirAndCopyInput("test")
        shell_safe(self.command + " -d test", pipe=True)
        shutil.copytree("test", "test_copy")
        shell_safe(self.command +
                   " -d test_copy -f BOUT.settings -o testsettings", pipe=True)

        with open("test_copy/testsettings") as f:
            contents = f.readlines()

            datadir = ""
            for line in contents:
                if line.startswith("datadir"):
                    # Assuming that this line looks like "datadir = <something> # comment"
                    datadir = line.split()[2]
                    break

            self.assertIn("test_copy", datadir,
                          msg="FAIL: datadir from command line clobbered by BOUT.settings")

    def testShortOptionsAreCleaned(self):
        self.makeDirAndCopyInput("test")
        shell_safe(self.command + " -d test", pipe=True)
        shutil.copytree("test", "test_copy")
        shell_safe(self.command +
                   " -d test_copy -f BOUT.settings -o testsettings", pipe=True)

        with open("test_copy/testsettings") as f:
            contents = f.read()
            self.assertNotIn("Command line", contents,
                             msg="FAIL: command line short options written to BOUT.settings")

    def testCommandLineOptionsArePrinted(self):
        self.makeDirAndCopyInput("test")
        shell_safe(self.command + " -d test", pipe=True)
        shutil.copytree("test", "test_copy")
        extra_options = ["-d", "test_copy", "-f", "BOUT.settings", "-o",
                         "testsettings", "-l", "bout.log", "--foo_flag", "some:option=value"]
        _, out = shell_safe(self.command + " " + " ".join(extra_options), pipe=True)

        command_line_options = None
        for line in out.splitlines():
            if line.lstrip().startswith("Command line"):
                command_line_options = line

        for option in extra_options:
            self.assertIn(option, command_line_options,
                          msg="FAIL: option {} not printed out".format(option))


if __name__ == "__main__":
    shell_safe("make")
    unittest.main(verbosity=2)
